use std::fs::File;
use std::io::{self, prelude::*, BufReader};
#[macro_use] extern crate lazy_static;
extern crate regex;
use regex::Regex;

fn main() -> io::Result<()>{

    let input = File::open("input.txt")?;
    let reader = BufReader::new(input);
    let mut valid_passport = 0;
    let mut valid_info_passport = 0;
    let mut passport_number = 0;
    let mut current_passport = "".to_string();
    for line in reader.lines() {
        let str = line?;
        if current_passport.len() != 0 && (str.len() == 0){
            passport_number += 1; 
            if is_passport_valid(current_passport.clone()){
                valid_passport += 1;
                if has_valid_info(current_passport.clone()){
                    valid_info_passport += 1;
                }
            }
            current_passport.clear();
        }else{
            current_passport += &(" ".to_owned() + &str);
        }
    }

    if current_passport.len() != 0 {// check the last passport if not already done
        passport_number += 1; 
        if is_passport_valid(current_passport.clone()){ 
            valid_passport += 1;
            if has_valid_info(current_passport.clone()){
                valid_info_passport += 1;
            }
        }
    }


    println!("On part 1 verification there are {}/{} valid passports ", valid_passport, passport_number);
    println!("On part 2 verification there are {}/{} valid passports ", valid_info_passport, passport_number);
    Ok(())
}
fn is_passport_valid(passport : String) -> bool {
    let mandatory_passport_key = vec!["byr",
                                      "iyr",
                                      "eyr",
                                      "hgt",
                                      "hcl",
                                      "ecl",
                                      "pid"];
    for key in &mandatory_passport_key{
        let is_invalid = !passport.contains(key);
        if is_invalid {
            //println!("current passport does not contain {}\n {}", key, passport);
            return false;
        }

    }

    return true;
}
fn has_valid_info(passport : String) -> bool{
    lazy_static!{
        static ref RE: Regex     = Regex::new(r"(\w{3}):([#\w]+)").unwrap();
        static ref RE_HGT: Regex = Regex::new(r"(\d+)(cm|in)").unwrap();
        static ref RE_HCL: Regex = Regex::new(r"^#[[:xdigit:]]{6}$").unwrap();
        static ref RE_ECL: Regex = Regex::new(r"^(amb|blu|brn|gry|grn|hzl|oth)$").unwrap();
        static ref RE_PID: Regex = Regex::new(r"^\d{9}$").unwrap();
    }

    for cap in RE.captures_iter(&passport){
        match &cap[1] {
            "byr" | "iyr" | "eyr"  => { 
                let date = (&cap[2]).parse::<u32>().unwrap(); 
                let mut min = 0;
                let mut max = 0;
                match &cap[1] {
                    "byr" => {
                        min = 1920;
                        max = 2002
                    },
                    "iyr" => {
                        min = 2010;
                        max = 2020
                    },
                    "eyr" => {
                        min = 2020;
                        max = 2030;
                    },
                    _ => {},
                }
                    if date < min || date > max {
                        println!("Wrong value in {} field : {}", &cap[1], &cap[2]);
                        return false;
                    }
            },
            "hgt" => {
                if !RE_HGT.is_match(&cap[2]) {println!("Wrong value in {} field : {}", &cap[1], &cap[2]); return false;}
                let second_cap = RE_HGT.captures(&cap[2]).unwrap();
                let mut min = 0;
                let mut max = 0;
                let height = (&second_cap[1]).parse::<u32>().unwrap();

                match &second_cap[2]{
                    "cm" => {
                        min = 150;
                        max = 193;
                    },
                    "in" => {
                        min = 59;
                        max = 76;
                    },
                    _ => {},   
                }

                if height < min || height > max {
                    println!("Wrong value in {} field : {}", &cap[1], &cap[2]);
                    return false;
                } 
            },
            "hcl" => {if !RE_HCL.is_match(&cap[2]){println!("Wrong value in {} field : {}", &cap[1], &cap[2]); return false;}},
            "ecl" => {if !RE_ECL.is_match(&cap[2]){println!("Wrong value in {} field : {}", &cap[1], &cap[2]); return false;}},
            "pid" => {if !RE_PID.is_match(&cap[2]){println!("Wrong value in {} field : {}", &cap[1], &cap[2]); return false;}},
            _ => {},

        }
    }
    return true;
}
